﻿#include "Transient.h"
#include "Application.h"
#include "Logging.h"
#include "Mesh.h"
#include "Output.h"
#include "System.h"
#include "UserObject.h"

#include <limits>

RegisterObject(Transient);

Transient::Transient(const Configuration& cfg)
  : Executioner(cfg)
  , _system(*(_app.GetSystem()))
  , _timer(_system.GetTimer())
  , _dt(Get<Real>("dt"))
  , _start_time(Get<Real>("start_time", 0))
  , _current_time(_start_time)
  , _num_steps(Get<int>("num_steps", std::numeric_limits<int>::max()))
  , _end_time(Get<Real>("end_time", std::numeric_limits<Real>::max()))
{
  _current_step = 0;

  _timer.Start();
}

void Transient::Init()
{
  _system.Init();

  for (auto& user_object : _app.GetUserObjectWarehouse())
  {
    user_object->Init();
  }

  for (auto& output : _app.GetOutputWarehouse())
  {
    output->Init();
  }
}

void Transient::PreExecute() {}

void Transient::Execute()
{
  PreExecute();

  while (KeepGoing())
  {
    PreStep();
    TakeStep();
    PostStep();
  }

  PostExecute();
}

void Transient::PostExecute()
{
  Success("运行完成.  运行时间:  ", _timer.GetElapsedTime());

  Info("当前步:", _current_step, "总步数:", _num_steps);
  Info("当前时间:", _current_time, "结束时间:", _end_time);
}


void Transient::PreStep()
{
  ComputeDT();
  fmt::print("Time Step {0}, time = {1}, dt = {2}\n", _current_step, _current_time, _dt);

  for (auto& user_object : _app.GetUserObjectWarehouse())
  {
    user_object->Execute();
  }

  for (auto& output : _app.GetOutputWarehouse())
  {
    output->Execute();
  }
}

void Transient::ComputeDT() {}

void Transient::TakeStep()
{
  //TODO: 求解前增加step，还是求解后增加step?
  _current_step++;
  _current_time += _dt;
  _system.Evolve();
}

void Transient::PostStep() {}

bool Transient::KeepGoing()
{
  bool keep_going = false;
  if (_current_step <= _num_steps && _current_time <= _end_time)
    keep_going = true;

  return keep_going;
}
